/* theater.cc

TODO: write a better description

*/
#include "copyright.h"
#include "system.h"
#include "theater.h"
#ifdef CHANGED
#include "synch.h"
#endif

#ifdef CHANGED
/* Movie Theater Simulation */

/* Global Variables */
const int NUM_ROWS = 5; /* number of rows in theater */
const int ROW_SIZE = 5; /* number of seats in each row */
const int MAX_TC = 5; /* maximum number of ticket clerks */
const int MAX_CC = 5; /* maximum number of concession clerks */
const int MAX_TT = 3; /* maximum number of ticket takers */
const int MAX_GROUPS = 60; /* TODO: not using this variable...rand()%10 
+ 1; maximum number of customer groups*/
int numGroups;
int numCustomers; /*counter to number the customers*/


/* Customer Data "Structure"*/
int customerNumber[MAX_GROUPS*5];
int customerGroupNumber[MAX_GROUPS*5];
int customerWantsPopcorn[MAX_GROUPS*5];
int customerWantsSoda[MAX_GROUPS*5];
int customerNeedsBathroom[MAX_GROUPS*5];
int customerIsHeadCustomer[MAX_GROUPS*5];
int customerSeatNumber[MAX_GROUPS*5];
int customerHasPopcorn[MAX_GROUPS*5];
int customerHasSoda[MAX_GROUPS*5];
	
/*Head Customer Information*/
int groupSize[MAX_GROUPS];
int groupPopcornSize[MAX_GROUPS];
int groupSodaSize[MAX_GROUPS];
int groupBathroomSize[MAX_GROUPS];
int groupMoney[MAX_GROUPS];
int groupTickets[MAX_GROUPS];
int headCustomerNumber[MAX_GROUPS]; /*the head customer's customer number*/
int customerState[MAX_GROUPS];
Lock* customerStateLock[MAX_GROUPS];

/*HeadCustomer - Regular Customer Interaction*/
Lock* headCustomerLock[MAX_GROUPS];
Condition* headCustomerConditionVariable[MAX_GROUPS];
Condition* regularCustomerConditionVariable[MAX_GROUPS];
	
/* Customer Finding Ticket Line */
Lock* ticketClerkLineLock; /* Lock for choosing a line */
Condition* ticketClerkLineConditionVariable[MAX_TC];
int ticketClerkLineCount[MAX_TC];
int ticketClerkState[MAX_TC]; /* 0 = NOT_BUSY, 1 = BUSY, 2 = ON_BREAK, -1 = NOT_AVAILABLE */

/* Customer - TicketClerk Interaction */
Lock* ticketClerkLock[MAX_TC]; /* Lock for Customer - TicketClerk Interaction */
Condition* ticketClerkConditionVariable[MAX_TC];
int ticketClerkRegister[MAX_TC]; /* registers for the ticket clerks */
int ticketClerkNumToSell[MAX_TC]; /* Number of tickets to sell in one transaction*/

/* Customer Finding Concession Line */
Lock* concessionClerkLineLock; /* Lock for choosing a line */
Condition* concessionClerkLineConditionVariable[MAX_CC];
int concessionClerkLineCount[MAX_CC];
int concessionClerkState[MAX_CC]; /* 0 = NOT_BUSY, 1 = BUSY, 2 = ON_BREAK, -1 = NOT_AVAILABLE */

/* Customer - ConcessionClerk Interaction */
Lock* concessionClerkLock[MAX_CC]; /* Lock for Customer - ConcessionClerk Interaction */
Condition* concessionClerkConditionVariable[MAX_CC];
int concessionClerkRegister[MAX_CC]; /*registers for the Concession clerks*/
int concessionClerkPopcornToSell[MAX_CC]; /*number of popcorn selling*/
int concessionClerkSodaToSell[MAX_CC]; /*number of sodas selling*/ 

/*Customer Finding TicketTaker Line*/
Lock* ticketTakerLineLock; /* Lock for choosing a line */
Condition* ticketTakerLineConditionVariable[MAX_TT];
int ticketTakerLineCount[MAX_TT];
int ticketTakerState[MAX_TT]; /* 0 = NOT_BUSY, 1 = BUSY, 2 = ON_BREAK, -1 = NOT_AVAILABLE */

/*Customer - TicketTaker Interaction*/
Lock* ticketTakerLock[MAX_TT]; /* Lock for Customer - TicketTaker Interaction */
Condition* ticketTakerConditionVariable[MAX_TT];
int ticketTakerCounter[MAX_TT];
int numberAdmitted;

/* Lobby variables */
Condition* lobbyConditionVariable;

/* Total register values */
int ticketMoney = 0;
int concessionMoney = 0;

/* Customer Finding Seat Interaction*/
int room[NUM_ROWS];
int seatsFilled = 0;
Lock* movieRoomLock; /* Lock for the room */
Condition* movieRoomConditionVariable;

/* Technician - Customer Interaction */
Lock* movieDataLock; /* Lock for the movie data */
Condition* technicianDataConditionVariable;

/* Manager - Technician Interaction */
int movieStartTime;
int movieEnded;
int movieLength;

/* Manager - End Simulation Information */
int custCounter;
Lock* counterLock;

/* Manager - Ticket Clerk break scenario */
Lock* ticketClerkBreakLock[MAX_TC];
Condition* ticketClerkBreakConditionVariable[MAX_TC];
int ticketClerkBreak[MAX_TC]; /* 1 = on break; 0 = off break; */

/* Manager - Concession Clerk break scenario */
Lock* concessionClerkBreakLock[MAX_CC];
Condition* concessionClerkBreakConditionVariable[MAX_CC];
int concessionClerkBreak[MAX_CC]; /* 1 = on break; 0 = off break; */

/* Manager - Ticket Taker break scenario */
Lock* ticketTakerBreakLock[MAX_TT];
Condition* ticketTakerBreakConditionVariable[MAX_TT];
int ticketTakerBreak[MAX_TT]; /* 1 = on break; 0 = off break; */

/*Bathroom Variables*/
Lock* bathroomLock[MAX_GROUPS];
Condition* bathroomLobbyConditionVariable[MAX_GROUPS];

void regularCustomer(int myIndex){

	/*BEGIN: RegularCustomer - HeadCustomer Interaction, Deciding on Food*/

	headCustomerLock[customerGroupNumber[myIndex]]->Acquire();

	/*STEP 1: RegularCustomer waits for Head customer to broadcast (ask them if they want food)*/
	printf("Customer %i of group %i is waiting for the group to form.\n", myIndex, customerGroupNumber[myIndex]);
	printf("Customer %i of group %i is waiting for the HeadCustomer.\n", myIndex, customerGroupNumber[myIndex]);
	regularCustomerConditionVariable[customerGroupNumber[myIndex]]->Wait(headCustomerLock[customerGroupNumber[myIndex]]);
	printf("Customer %i of group %i has been told by the HeadCustomer to proceed.\n", myIndex, customerGroupNumber[myIndex]);
  
	/*STEP 2: The customer is asked by the head, andx the regular customer decides if they want food.*/
	customerWantsPopcorn[myIndex] = (rand()%4 > 0) ? 1 : 0;
	customerWantsSoda[myIndex] = (rand()%4 > 0) ? 1 : 0;
	
	printf("Customer %i in group %i wants %i popcorn and %i soda.\n", myIndex, customerGroupNumber[myIndex],customerWantsPopcorn[myIndex],customerWantsSoda[myIndex]);
	
	printf("Customer %i in Group %i has %i popcorn and %i soda request from a group member\n", headCustomerNumber[customerGroupNumber[myIndex]], customerGroupNumber[myIndex], customerWantsPopcorn[myIndex], customerWantsSoda[myIndex]);
	

	headCustomerConditionVariable[customerGroupNumber[myIndex]]->Signal(headCustomerLock[customerGroupNumber[myIndex]]);
	regularCustomerConditionVariable[customerGroupNumber[myIndex]]->Wait(headCustomerLock[customerGroupNumber[myIndex]]);

	/*END: RegularCustomer - HeadCustomer Interaction, Deciding on Food*/
	
	/*BEGIN: RegularCustomer - HeadCustomer Interaction, Getting line from head customer*/
	
	printf("Customer %i in group %i is sitting in a theater room seat.\n", myIndex, customerGroupNumber[myIndex]);

	//printf("(RCust%i, group%i: I'm in seat %i.)\n", myIndex, customerGroupNumber[myIndex], customerSeatNumber[myIndex]);

	headCustomerConditionVariable[customerGroupNumber[myIndex]]->Signal(headCustomerLock[customerGroupNumber[myIndex]]);
	regularCustomerConditionVariable[customerGroupNumber[myIndex]]->Wait(headCustomerLock[customerGroupNumber[myIndex]]);

	printf("Customer %i in group %i is getting out of a theater room seat.\n", myIndex, customerGroupNumber[myIndex]);

	
	/*END: RegularCustomer - HeadCustomer Interaction, Getting line from head customer*/

	/*BEGIN: Bathroom deciding*/
	

	customerNeedsBathroom[myIndex] = (rand()%4 > 0) ? 0 : 1;
	
	if(customerNeedsBathroom[myIndex]){
		printf("Customer %i in Group %i is going to the bathroom.\n", myIndex, customerGroupNumber[myIndex]);
	}
	
	headCustomerConditionVariable[customerGroupNumber[myIndex]]->Signal(headCustomerLock[customerGroupNumber[myIndex]]);
	regularCustomerConditionVariable[customerGroupNumber[myIndex]]->Wait(headCustomerLock[customerGroupNumber[myIndex]]);


	if(customerNeedsBathroom[myIndex] == 0){

		
	
		bathroomLock[customerGroupNumber[myIndex]]->Acquire();

		headCustomerConditionVariable[customerGroupNumber[myIndex]]->Signal(headCustomerLock[customerGroupNumber[myIndex]]);

	 //regularCustomerConditionVariable[customerGroupNumber[myIndex]]->Wait(headCustomerLock[customerGroupNumber[myIndex]]);

		
		//headCustomerLock[customerGroupNumber[myIndex]]->Release();
		//bathroomLobbyConditionVariable[customerGroupNumber[myIndex]]->Wait(bathroomLock[customerGroupNumber[myIndex]]);

		
		
		bathroomLock[customerGroupNumber[myIndex]]->Release();
		
	}
	else{
		
		
	
		bathroomLock[customerGroupNumber[myIndex]]->Acquire();

		groupBathroomSize[customerGroupNumber[myIndex]]--;	
		
		//printf("(RCust%i: Done going to the bathroom  There are still %i people we're waiting for.)\n", myIndex,groupBathroomSize[customerGroupNumber[myIndex]]);

		bathroomLock[customerGroupNumber[myIndex]]->Release();
		
		if(groupBathroomSize[customerGroupNumber[myIndex]] == 0){
			bathroomLobbyConditionVariable[customerGroupNumber[myIndex]]->Broadcast(bathroomLock[customerGroupNumber[myIndex]]);
		}

		headCustomerConditionVariable[customerGroupNumber[myIndex]]->Signal(headCustomerLock[customerGroupNumber[myIndex]]);
			
		printf("Customer %i in Group %i is leaving the bathroom.\n", myIndex, customerGroupNumber[myIndex]);
	
	}
	
	regularCustomerConditionVariable[customerGroupNumber[myIndex]]->Wait(headCustomerLock[customerGroupNumber[myIndex]]);

	//printf("(RCust%i: end bathroom deciding %i)\n", myIndex, customerGroupNumber[myIndex]);
	/*END: Bathroom deciding*/
	
	headCustomerLock[customerGroupNumber[myIndex]]->Release();
	
	
}


void headCustomer(int myIndex){

	int flag = 1;
		
	//printf("HCust%i: I am a head customer with groupsize = %i\n", myIndex, groupSize[myIndex] + 1);
	
	/*BEGIN: Customer - TicketClerk Interaction*/
	
	int myTicketClerk = -1; /* index = -1 */
	
	while(flag){
		//printf("HCust%i: while flagging a ticket clerk\n", myIndex);
		ticketClerkLineLock->Acquire(); /* Lock for choosing a line */
		
		/* look for a clerk in the NOT_BUSY state */
		for(int i = 0; i < MAX_TC; i++){
			/* need to have a check to see if the clerk "exists" and is NOT_BUSY */
			if(ticketClerkState[i] == 0){
				/* don't have to wait, just go to clerk */
				myTicketClerk = i;
				ticketClerkState[i] = 1;
				
				printf("Customer %i in Group %i is walking up to TicketClerk %i to buy %i tickets\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex],myTicketClerk, groupSize[myIndex] + 1);
				
				
				flag = 0;
				break;
			}
		}
		
		/* if I don't have a clerk (myTicketClerk = -1), choose shortest line */
		if(myTicketClerk == -1){
			//printf("HCust%i: Finding the shortest line\n", myIndex);
			int shortestTicketClerkLine = 0; /* index = 0 */
			int shortestTicketClerkLineLength = ticketClerkLineCount[0];
			
			/* need to find a starting line that isn't on break */
			for(int i = 0; i < MAX_TC; i++){
				if(ticketClerkState[i] == 1){
					//printf("HCust%i: attempting to acquire TC%i's lock to get shortest line\n", myIndex, i);
					ticketClerkBreakLock[i]->Acquire();
					if(ticketClerkBreak[i] == 0){
						//printf("HCust%i: found an off break line at TC%i\n", myIndex, i);
						shortestTicketClerkLine = i;
						shortestTicketClerkLineLength = ticketClerkLineCount[i];
					}
					ticketClerkBreakLock[i]->Release();
				}
			}
			
			for(int i = 0; i < MAX_TC; i++){
				if(ticketClerkState[i] == 1){
					ticketClerkBreakLock[i]->Acquire();
					if(shortestTicketClerkLineLength >= ticketClerkLineCount[i] && ticketClerkBreak[i] == 0){ /* if there's a shorter line than current line */
						//printf("HCust%i: found a shorter line at TC%i\n", myIndex, i);
						shortestTicketClerkLine = i;
						shortestTicketClerkLineLength = ticketClerkLineCount[i];
					}
					ticketClerkBreakLock[i]->Release();
				}
			}
			
			/* Steps
			1. I must have the shortest line at this point 
			2. Get in that line 
			3. Sleep and give up the lock, will reacquire the lock when signaled */
			
			//printf("HCust%i: Getting in a line\n", myIndex);
			myTicketClerk = shortestTicketClerkLine;
			printf("Customer %i in Group %i is getting in TicketClerk line %i\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], myTicketClerk);
			ticketClerkLineCount[myTicketClerk]++;
			ticketClerkLineConditionVariable[myTicketClerk]->Wait(ticketClerkLineLock);
			
			//printf("HCust%i: i will now try to take TC%i's break lock and i have the ticket clerk line lock\n", myIndex, myTicketClerk);
			ticketClerkBreakLock[myTicketClerk]->Acquire();
			//printf("HCust%i: TC%i's break lock acquired\n", myIndex, myTicketClerk);
			if(ticketClerkBreak[myTicketClerk] == 1){
				
				printf("Customer %i in Group %i sees TicketClerk %i is on break.\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], myTicketClerk);
				ticketClerkLineCount[myTicketClerk]--;
				
				ticketClerkLineLock->Release();
				ticketClerkBreakLock[myTicketClerk]->Release();
				
				myTicketClerk = -1;
			} else if(ticketClerkBreak[myTicketClerk] == 2){
				//printf("HCust%i: my TC%i is taking too long, gotta find a new line\n", myIndex, myTicketClerk);
				ticketClerkLineCount[myTicketClerk]--;
				
				if(ticketClerkLineCount[myTicketClerk] == 0){
					//printf("HCust%i: TC%i line count == 0\n", myIndex, myTicketClerk);
					ticketClerkBreak[myTicketClerk] = 0;
				}
				
				ticketClerkLineLock->Release();
				ticketClerkBreakLock[myTicketClerk]->Release();
				
				myTicketClerk = -1;
			} else {
				//printf("HCust%i: my TC%i isn't on break and doesn't have a huge line. onward!\n", myIndex, myTicketClerk);
				flag = 0;
				ticketClerkBreakLock[myTicketClerk]->Release();
			}
		}
	}
	
	flag = 1;
	//printf("HCust%i: releasing the kraken on TC%i \n", myIndex, myTicketClerk);
	ticketClerkLineLock->Release();
	ticketClerkLock[myTicketClerk]->Acquire();
	ticketClerkBreakLock[myTicketClerk]->Acquire();
	
	/*STEP 1: Customer-TicketClerk, Sets the global variable indicating the number of tickets he wants to buy.*/
	//printf("HCust%i: Hello, TC%i I need %i tickets\n", myIndex, myTicketClerk, (groupSize[myIndex] + 1));
	ticketClerkNumToSell[myTicketClerk] = (groupSize[myIndex] + 1);
	
	ticketClerkConditionVariable[myTicketClerk]->Signal(ticketClerkLock[myTicketClerk]);
	ticketClerkConditionVariable[myTicketClerk]->Wait(ticketClerkLock[myTicketClerk]);

	/*STEP 2: Customer-TicketClerk, Customer hands out the cash.*/
	printf("Customer %i in Group %i in TicketClerk line %i is paying %i for tickets\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], myTicketClerk, (groupSize[myIndex] + 1)*12);
	
	ticketClerkConditionVariable[myTicketClerk]->Signal(ticketClerkLock[myTicketClerk]);
	ticketClerkConditionVariable[myTicketClerk]->Wait(ticketClerkLock[myTicketClerk]);
	
	/*STEP 3: Customer-TicketClerk, After the ticket clerks sells the tickets, he takes the tickts (sets groupTickets)*/
	
	groupTickets[myIndex] = groupSize[myIndex] + 1;

	ticketClerkConditionVariable[myTicketClerk]->Signal(ticketClerkLock[myTicketClerk]);
	
	printf("Customer %i in Group %i is leaving TicketClerk%i\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], myTicketClerk);
	ticketClerkBreakLock[myTicketClerk]->Release();
	ticketClerkLock[myTicketClerk]->Release();
	
	//printf("HCust%i: I have $%i left in my wallet.\n", myIndex, groupMoney[myIndex]);
	
	/*END: Customer - TicketClerk Interaction*/
	
	/*BEGIN: HeadCustomer - RegularCustomer Interaction for Concessions*/
	 

	/*STEP 1: HeadCustomer - RegularCustomer, Tells all of his "friends" that he's going to order food for them*/
	
	/*Only if the head customer has group members should be acquire the lock, otherwise skip to deciding only for himself*/
	
	if(groupSize[myIndex] > 0){
	
		headCustomerLock[myIndex]->Acquire();
						
		/*Asking each one at a time if they want food, then waiting for the next.*/
		printf("HeadCustomer %i of group %i has told the group to proceed.\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex]);
		for(int i = 0; i < groupSize[myIndex]; i++){
			regularCustomerConditionVariable[myIndex]->Signal(headCustomerLock[myIndex]);
			headCustomerConditionVariable[myIndex]->Wait(headCustomerLock[myIndex]);
		}		
			
		/*STEP 2: The headcustomer decides about food himself, and then tallies the total*/
		customerWantsPopcorn[headCustomerNumber[myIndex]] = (rand()%4 > 0) ? 1 : 0;
		customerWantsSoda[headCustomerNumber[myIndex]] = (rand()%4 > 0) ? 1 : 0;
		
		printf("Customer %i in group %i wants %i popcorn and %i soda.\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], customerWantsPopcorn[myIndex], customerWantsSoda[myIndex]);
		
				
		groupPopcornSize[myIndex] = 0;
		
		for(int i = myIndex; i < (myIndex + groupSize[myIndex] + 1); i++){
			if(customerWantsPopcorn[i]){
				groupPopcornSize[myIndex]++;
			}
		}
		
		groupSodaSize[myIndex] = 0;
		
		for(int i = myIndex; i < (myIndex + groupSize[myIndex] + 1); i++){
			if(customerWantsSoda[i]){
				groupSodaSize[myIndex]++;
			}
		}
		
		headCustomerLock[myIndex]->Release();
	}
	else{
		/*COPIED from STEP 2: The headcustomer decides about food himself only*/
		customerWantsPopcorn[headCustomerNumber[myIndex]] = (rand()%4 > 0) ? 1 : 0;
		customerWantsSoda[headCustomerNumber[myIndex]] = (rand()%4 > 0) ? 1 : 0;
		groupPopcornSize[myIndex] = customerWantsPopcorn[headCustomerNumber[myIndex]];
		groupSodaSize[myIndex] = customerWantsSoda[headCustomerNumber[myIndex]];
		
		printf("Customer %i in group %i wants %i popcorn and %i soda.\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], customerWantsPopcorn[myIndex], customerWantsSoda[myIndex]);
		
	}	
	
	
	/*END: HeadCustomer - RegularCustomer Interaction for Concessions*/
	
	/*BEGIN: Customer - ConcessionClerk Interaction*/
	
	if(groupPopcornSize[myIndex] > 0 || groupSodaSize[myIndex] > 0){
	
		int myConcessionClerk = -1; /* index = -1 */
		
		while(flag){
			//printf("HCust%i: while flagging a concession clerk\n", myIndex);
			concessionClerkLineLock->Acquire(); /* Lock for choosing a line */
			/* look for a clerk in the NOT_BUSY state */
			for(int i = 0; i < MAX_CC; i++){
				/* need to have a check to see if the clerk "exists" and is NOT_BUSY */
				if(concessionClerkState[i] == 0){
					/* don't have to wait, just go to clerk */
					myConcessionClerk = i;
					concessionClerkState[i] = 1;
					printf("Customer %i in Group %i is walking up to ConcessionClerk%i to buy %i popcorn and %i soda.\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex],myConcessionClerk, groupPopcornSize[myIndex], groupSodaSize[myIndex]);
					flag = 0;
					break;
				}
			}
			
			/* if I don't have a clerk (myConcessionClerk = -1), choose shortest line */
			if(myConcessionClerk == -1){
				//printf("HCust%i: Finding the shortest food line\n", myIndex);
				int shortestConcessionLine = 0; /* index = 0 */
				int shortestConcessionLineLength = concessionClerkLineCount[0];
				
				for(int i = 0; i < MAX_CC; i++){
					if(concessionClerkState[i] == 1){
						concessionClerkBreakLock[i]->Acquire();
						if(concessionClerkBreak[i] == 0){
							shortestConcessionLine = i;
							shortestConcessionLineLength = concessionClerkLineCount[i];
						}
						concessionClerkBreakLock[i]->Release();
					}
				}
				
				for(int i = 1; i < MAX_CC; i++){
					if(concessionClerkState[i] == 1){
						concessionClerkBreakLock[i]->Acquire();
						if(shortestConcessionLineLength >= concessionClerkLineCount[i] && concessionClerkBreak[i] == 0){ /* if there's a shorter line than current line and avaliable*/	
							shortestConcessionLine = i;
							shortestConcessionLineLength = concessionClerkLineCount[i];
						}
						concessionClerkBreakLock[i]->Release();
					}
				}
				
				/* Steps
				1. I must have the shortest line at this point 
				2. Get in that line 
				3. Sleep and give up the lock, will reacquire the lock when signaled */
				
				//printf("HCust%i: Getting in a concession line\n", myIndex);
				myConcessionClerk = shortestConcessionLine;
				printf("Customer %i in Group %i is getting in ConcessionClerk line %i\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], myConcessionClerk);
				concessionClerkLineCount[myConcessionClerk]++;
				concessionClerkLineConditionVariable[myConcessionClerk]->Wait(concessionClerkLineLock);
				
				concessionClerkBreakLock[myConcessionClerk]->Acquire();
				if(concessionClerkBreak[myConcessionClerk] == 1){
					//concessionClerkLineCount[myConcessionClerk]--;
					
					printf("Customer %i in Group %i sees ConcessionClerk %i is on break.\n",headCustomerNumber[myIndex], customerGroupNumber[myIndex], myConcessionClerk);
					concessionClerkLineLock->Release();
					concessionClerkBreakLock[myConcessionClerk]->Release();
					
					myConcessionClerk = -1;
				} else if(concessionClerkBreak[myConcessionClerk] == 2){
					//concessionClerkLineCount[myConcessionClerk]--;
					concessionClerkBreak[myConcessionClerk] = 0;
					
					concessionClerkLineLock->Release();
					concessionClerkBreakLock[myConcessionClerk]->Release();
					
					myConcessionClerk = -1;
				} else {
					flag = 0;
					concessionClerkBreakLock[myConcessionClerk]->Release();
				}
			}
		}
		
		flag = 1;
		concessionClerkLineLock->Release();
		concessionClerkLock[myConcessionClerk]->Acquire();
		concessionClerkBreakLock[myConcessionClerk]->Acquire();
		
		/*STEP 1: Customer-ConcessionClerk, Tells Concession clerk here's there and read to order.*/
		//printf("HCust%i: Hello CC%i, I need %i popcorns and %i sodas!\n", myIndex, myConcessionClerk, groupPopcornSize[myIndex], groupSodaSize[myIndex]);
		
		concessionClerkPopcornToSell[myConcessionClerk] = groupPopcornSize[myIndex];
		concessionClerkSodaToSell[myConcessionClerk] = groupSodaSize[myIndex];
		
		concessionClerkConditionVariable[myConcessionClerk]->Signal(concessionClerkLock[myConcessionClerk]);
		concessionClerkConditionVariable[myConcessionClerk]->Wait(concessionClerkLock[myConcessionClerk]);
		
		/*STEP 2: Customer-ConcessionClerk, Customer hands out the cash*/
		
		printf("Customer %i in Group %i in ConcessionClerk line %i is paying %i for food\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], myConcessionClerk, (groupPopcornSize[myIndex]*5 + groupSodaSize[myIndex]*4));

		groupMoney[myIndex] -= groupPopcornSize[myIndex]*5 + groupSodaSize[myIndex]*4;
		
		concessionClerkConditionVariable[myConcessionClerk]->Signal(concessionClerkLock[myConcessionClerk]);
		concessionClerkConditionVariable[myConcessionClerk]->Wait(concessionClerkLock[myConcessionClerk]);
		
		/*STEP 3: Customer-ConcessionClerk, After the concession clerks sells the food, he takes the food*/
		printf("Customer %i in Group %i is leaving ConcessionClerk%i\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], myConcessionClerk);
		
		/*TODO: Acknowledge that the purchase of food went through somehow.*/

		concessionClerkConditionVariable[myConcessionClerk]->Signal(concessionClerkLock[myConcessionClerk]);
		
		//printf("HCust%i: I'm done buying food and to the Ticket Taker!\n", myIndex);
		concessionClerkBreakLock[myConcessionClerk]->Release();
		concessionClerkLock[myConcessionClerk]->Release();
	
		//printf("HCust%i: I have $%i left in my wallet.\n", myIndex, groupMoney[myIndex]);
	}	
	
	/*END: Customer - ConcessionClerk Interaction*/
			
	/*BEGIN: Customer - TicketTaker Interaction*/
	
	while(1){
		int myTicketTaker = -1; /* index = -1 */
		
		while(flag){
			//printf("HCust%i: about to acquire ticket taker line lock to find a line\n", myIndex);
			ticketTakerLineLock->Acquire();
			//printf("HCust%i: acquired ticket taker line lock to find a line\n", myIndex);
			/* Look to find TixTaker that isn't busy */
			for(int i = 0; i < MAX_TT; i++){
				if(ticketTakerState[i] == 0){
					myTicketTaker = i;
					ticketTakerState[i] = 1;
					printf("Customer %i in Group %i is walking up to TicketTaker%i to give %i tickets.\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], myTicketTaker, (groupSize[myIndex] + 1));
					flag = 0;
					break;
				}
			}
			/* TixTakers are all busy, will now look for shortest line */
			if(myTicketTaker == -1){
				//printf("HCust%i: Finding the shortest ticket taker line\n", myIndex);
				int shortestTicketTakerLine = 0; 
				int shortestTicketTakerLineLength = ticketTakerLineCount[0];
				
				for(int i = 0; i < MAX_TT; i++){
					if(ticketTakerState[i] == 1){
						ticketTakerBreakLock[i]->Acquire();
						if(ticketTakerBreak[i] == 0){
							shortestTicketTakerLine = i;
							shortestTicketTakerLineLength = ticketTakerLineCount[i];
						}
						ticketTakerBreakLock[i]->Release();
					}
				}
				
				for(int i = 1; i < MAX_TT; i++){
					if(ticketTakerState[i] == 1){
						ticketTakerBreakLock[i]->Acquire();
						if((shortestTicketTakerLineLength >= ticketTakerLineCount[i]) && ticketTakerBreak[i] == 0){
							/* Shorter line found, will now update shortest line */
							shortestTicketTakerLine = i;
							shortestTicketTakerLineLength = ticketTakerLineCount[i];
						}
						ticketTakerBreakLock[i]->Release();
					}
				}
				
				//printf("HCust%i: Getting in a ticket taker line\n", myIndex);
				myTicketTaker = shortestTicketTakerLine;
				printf("Customer %i in Group %i is getting in TicketTaker line %i\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], myTicketTaker);
				ticketTakerLineCount[myTicketTaker]++;
				ticketTakerLineConditionVariable[myTicketTaker]->Wait(ticketTakerLineLock);
				//printf("HCust%i: reacquired TT%i ticket taker line lock after waiting in line going to check if he's on break\n", myIndex, myTicketTaker);
				
				ticketTakerBreakLock[myTicketTaker]->Acquire();
				if(ticketTakerBreak[myTicketTaker] == 1){
					printf("Customer %i in Group %i sees TicketTaker %i is on break.\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], myTicketTaker);
					ticketTakerLineCount[myTicketTaker]--;
					
					ticketTakerLineLock->Release();
					//printf("HCust%i: released TT%i ticket taker line lock TTBreak == 1\n", myIndex, myTicketTaker);
					ticketTakerBreakLock[myTicketTaker]->Release();
					
					myTicketTaker = -1;
				} else if (ticketTakerBreak[myTicketTaker] == 2){
					//printf("HCust%i: my TT%i is taking too long, gotta find a new line\n", myIndex, myTicketTaker);
					ticketTakerLineCount[myTicketTaker]--;
					
					if(ticketTakerLineCount[myTicketTaker] == 0){
						//printf("HCust%i: TT%i line count == 0\n", myIndex, myTicketTaker);
						ticketTakerBreak[myTicketTaker] = 0;
					}
					
					ticketTakerLineLock->Release();
				//	printf("HCust%i: released TT%i ticket taker line lock TTBreak == 2\n", myIndex, myTicketTaker);
					ticketTakerBreakLock[myTicketTaker]->Release();
					
					myTicketTaker = -1;
				} else {
					//printf("HCust%i: my TT%i isn't on break and doesn't have a huge line. onward!\n", myIndex, myTicketTaker);
					flag = 0;
					ticketTakerBreakLock[myTicketTaker]->Release();
				}
				/* Cust is now in line waiting to be signaled to come to the counter */
			}
		}
	
		flag = 1;
		//printf("HCust%i: trying to release ticket taker line lock to start interaction\n", myIndex);
		ticketTakerLineLock->Release();
		//printf("HCust%i: released ticket taker line lock, trying to acquire TT%i ticket taker lock\n", myIndex, myTicketTaker);
		ticketTakerLock[myTicketTaker]->Acquire();
		//printf("HCust%i: trying to acquire the TT%i's break lock\n", myIndex, myTicketTaker);
		ticketTakerBreakLock[myTicketTaker]->Acquire();
		//printf("HCust%i: acquired the TT%i's break lock\n", myIndex, myTicketTaker);
		//printf("HCust%i: TT%i ticket taker lock acquired\n", myIndex, myTicketTaker);
		/* Customer is now at counter */
		
		//printf("HCust%i: Hello, TT%i I have %i tickets\n", myIndex, myTicketTaker, groupSize[myIndex]+1);
		ticketTakerCounter[myTicketTaker] = groupSize[myIndex]+1;
		
		ticketTakerConditionVariable[myTicketTaker]->Signal(ticketTakerLock[myTicketTaker]);
		//printf("HCust%i: about to wait on TT%i ticket taker lock\n", myIndex, myTicketTaker);
		ticketTakerConditionVariable[myTicketTaker]->Wait(ticketTakerLock[myTicketTaker]);
		//printf("HCust%i: reacquired TT%i ticket taker lock\n", myIndex, myTicketTaker);
		
		ticketTakerBreakLock[myTicketTaker]->Release();
		if(ticketTakerCounter[myTicketTaker] == 1){
			ticketTakerCounter[myTicketTaker] = -1;
			ticketTakerConditionVariable[myTicketTaker]->Signal(ticketTakerLock[myTicketTaker]);
			printf("Customer %i in Group %i is leaving TicketTaker%i\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], myTicketTaker);
			ticketTakerLock[myTicketTaker]->Release();
			//printf("HCust%i: released TT%i ticket taker lock\n", myIndex, myTicketTaker);
			break;
		} else {
			ticketTakerCounter[myTicketTaker] = -1;
			ticketTakerConditionVariable[myTicketTaker]->Signal(ticketTakerLock[myTicketTaker]);
			//printf("HCust%i: Why is TT%i such a negative nancy?\n", myIndex, myTicketTaker);
			ticketTakerLock[myTicketTaker]->Release();
			//printf("HCust%i: released TT%i ticket taker lock, trying to acquire ticket taker line lock\n", myIndex, myTicketTaker);
			ticketTakerLineLock->Acquire();
			//printf("\t\t\t\t\t\tHCust%i: going to the lobby\n", myIndex);
			printf("Customer %i in Group %i sees TicketTaker %i is no longer taking tickets. Going to the lobby.\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], myTicketTaker);
			printf("Customer %i in Group %i is in the lobby.\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex]);
			lobbyConditionVariable->Wait(ticketTakerLineLock);
			printf("Customer %i in Group %i is leaving the lobby.\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex]);
			//printf("HCust%i: reacquired TT%i ticket taker line lock, about to release\n", myIndex, myTicketTaker);
			ticketTakerLineLock->Release();
			//printf("HCust%i: released TT%i ticket taker line lock\n", myIndex, myTicketTaker);
		}
	}
	
	/*END: Customer - TicketTaker Interaction*/
	/* BEGIN: Customer - Movie Technician Interaction, finding a seat */
	/* 
	A.	find seats
	B.	wait for movie to start/finish
	C.	go bathroom, if needed
	*/
	//printf("HCust%i: about to acquire movie room lock\n", myIndex);
	movieRoomLock->Acquire(); /* Acquire the room lock */
	//printf("HCust%i: acquired movie room lock about to acquire head customer lock\n", myIndex);
	headCustomerLock[myIndex]->Acquire();
	//printf("HCust%i: i now have head customer lock and movie room lock\n", myIndex);
	
	/* 
	A. find seats 
		1.	find row that fits whole group
		2.	tell customers their seat numbers
		3.	add self to row
	*/
	int foundRow = 0;
	for(int i = 0; i < NUM_ROWS; i++){
		if((room[i] + groupSize[myIndex] + 1) <= ROW_SIZE){
			foundRow = 1; /* found row */
			int seatNumber = room[i];
			for(int j = 0; j < numCustomers; j++){


				if(myIndex == customerGroupNumber[j]){
					/*Rows are numbered with the ten's digit = row, one's = column.
					So, Seat 3 -> row 0, col 3.  Seat 14 -> row 1, col 4
					*/
					customerSeatNumber[j] = i*10+seatNumber;
					printf("Customer %i in Group %i has found the following seat: row %i and seat %i\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], i, seatNumber);
					
					if(customerIsHeadCustomer[j] == 1){
					//	printf("HCust%i: I'm in seat %i\n", myIndex, customerSeatNumber[j]);
					}
					
					seatNumber++;
					/*END: HeadCustomer-RegularCustomer Interaction, telling seats*/

				}
			}
			room[i] += (groupSize[myIndex] + 1); /* add group to row */
			seatsFilled += (groupSize[myIndex] + 1);

			break; /* don't need to keep checking for rows */
		}
	}
	
	/* if no row found
		1. disperse to any available seats
		this is really inefficient, perhaps a better way?
	*/
	if(foundRow == 0){
		int tempGroupSize = (groupSize[myIndex] + 1);
		for(int i = 0; i < NUM_ROWS; i++){
			if(tempGroupSize == 0){ /* the whole group is seated */
				break; 
			} else { /* whole group is not seated CHECK MATH HERE*/
				
				for(int j = room[i]; j < ROW_SIZE; j++){ /* j = seatNumber */
					for(int k = 0; k < numCustomers; k++){
						if(myIndex == customerGroupNumber[k] && customerSeatNumber[k] == -1){ /* if customer is in group and does not have a seat */
							customerSeatNumber[k] = i*10 + j;
							
							printf("Customer %i in Group %i has found the following seat: row %i and seat %i\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex], i, j);

							
							if(customerIsHeadCustomer[k] == 1){
								//printf("HCust%i: I'm in seat %i\n", k, customerSeatNumber[k]);
							}
							/* ping pong with customer here */
							break; /* seat is filled */
						}
					}
					room[i] += tempGroupSize;
					tempGroupSize -= (ROW_SIZE - room[i]); /* people leave group to sit */
				}				
			}
		}
		
		/* group should all be seated at this point */
		seatsFilled += (groupSize[myIndex] + 1);
	}
	
	/*Telling all of the customers their seats.*/
	for(int k = 0; k < groupSize[myIndex]; k++){
		regularCustomerConditionVariable[myIndex]->Signal(headCustomerLock[myIndex]);
		//printf("HCust%i: %i about to wait on head customer lock, just writing movie room lock\n", myIndex, groupSize[myIndex]);
		headCustomerConditionVariable[myIndex]->Wait(headCustomerLock[myIndex]);
		//printf("HCust%i: %i reacquired head customer lock, just writing movie room lock\n", myIndex, groupSize[myIndex]);
	}
	
	/* B. wait for movie to start and finish */
	//printf("HCust%i: about to wait on movie room lock\n", myIndex);
	//movieRoomConditionVariable->Wait(movieRoomLock);
	//printf("HCust%i: reacquired movie room lock, about to release movie room lock\n", myIndex);
	movieRoomLock->Release();
	//printf("HCust%i: released movie room lock\n", myIndex);
	
	/* END: Customer finding a seat */
	
	/* BEGIN: Customers in the bathroom*/
	
	if(groupSize[myIndex] > 0){

		

		//STEP 1: Asking each one if they need to go to the bathrrom
		for(int i = 0; i < groupSize[myIndex]; i++){
			regularCustomerConditionVariable[myIndex]->Signal(headCustomerLock[myIndex]);
			headCustomerConditionVariable[myIndex]->Wait(headCustomerLock[myIndex]);
		}		

		bathroomLock[myIndex]->Acquire();
		customerNeedsBathroom[headCustomerNumber[myIndex]] = (rand()%4 > 0) ? 0 : 1;
		
		if(customerNeedsBathroom[headCustomerNumber[myIndex]]){
			//printf("HCust%i: I need to go to the bathroom!\n",myIndex);
		}
		else{
			//printf("HCust%i: I don't need to go to the bathroom!\n",myIndex);

		}
		
		bathroomLock[myIndex]->Release();

		groupBathroomSize[myIndex] = 0;

		for(int i = myIndex; i < (myIndex + groupSize[myIndex] + 1); i++){
			if(customerNeedsBathroom[i]){
				printf("Customer %i in Group %i is going to the bathroom.\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex]);
				bathroomLock[myIndex]->Acquire();
				groupBathroomSize[myIndex]++;
				bathroomLock[myIndex]->Release();
			}
		}

		
		//printf("HCust%i: I'll wait for %i people to go to the bathroon.\n",myIndex,groupBathroomSize[myIndex]);

	}
	else{
	
		customerNeedsBathroom[headCustomerNumber[myIndex]] = (rand()%4 > 0) ? 0 : 1;
		
		if(customerNeedsBathroom[headCustomerNumber[myIndex]]){
		
			for(int i = 0; i < 20; i++){
				currentThread->Yield();
			}
		
		}
		
		groupBathroomSize[myIndex] = 0;

	}
	

	
	//Step 2: Allowing the customers to go to the bathroom, or wait in the lobby
	for(int i = 0; i < groupSize[myIndex]; i++){
	
			regularCustomerConditionVariable[myIndex]->Signal(headCustomerLock[myIndex]);

			headCustomerConditionVariable[myIndex]->Wait(headCustomerLock[myIndex]);
			
			

	}
	
	
	//Step 3: Head customer goes to the lobby himself
	if(groupBathroomSize[myIndex] > 0 && groupSize[myIndex] > 0){

		bathroomLock[myIndex]->Acquire();
		
		groupBathroomSize[myIndex]--;
		
		bathroomLock[myIndex]->Release();
		
		printf("Customer %i in Group %i is leaving the bathroom.\n", headCustomerNumber[myIndex], customerGroupNumber[myIndex]);

	}

	/* END: Customers going to the bathroom */
	
	counterLock->Acquire();
	custCounter -= (groupSize[myIndex]+1);
	//printf("HCust%i: all done! let's get out of here. %i left\n", myIndex, custCounter);
	counterLock->Release();

	headCustomerLock[myIndex]->Release();
}


void ticketClerk(int myIndex){
	while(1){ /* while true */
		ticketClerkLineLock->Acquire(); /* Lock for choosing a line */
		//printf("\tTC%i: line length:%i\n", myIndex, ticketClerkLineCount[myIndex]);
		printf("TicketClerk %i has a line length %i and is signaling a customer.\n", myIndex, ticketClerkLineCount[myIndex]);
		/* check if there is a customer in my line */
		if(ticketClerkLineCount[myIndex] > 0){ /* There is someone in my line */
			//printf("\tTC%i: Someone is in my line!\n", myIndex);
			/* Steps
			1. set my state to busy
			2. decrement line count
			3. wake up 1 customer */
			
			ticketClerkState[myIndex] = 1; /* state = BUSY */
			ticketClerkLineCount[myIndex]--; /* decrement line count */
			ticketClerkLineConditionVariable[myIndex]->Signal(ticketClerkLineLock);
		} else { /* no one is in my line */
			/* Steps
			1. set my state to not_busy */
			
			//printf("\tTC%i: No one is in my line D:\n", myIndex);
			ticketClerkState[myIndex] = 0; /* state = NOT_BUSY */
		}
		
		/* done with clerk's first monitor.
		   clerk is ready to wait
		   by acquiring the next lock before releasing the current lock,
		   we guarantee that we get the lock first */		
		ticketClerkLock[myIndex]->Acquire();
		//printf("\tTC%i: releasing line lock and starting interaction\n", myIndex);
		ticketClerkLineLock->Release();
		
		/*STEP 1: TicketClerk-Customer, Waiting for the customer to come up to ticket window so it can begin.*/		
		ticketClerkConditionVariable[myIndex]->Wait(ticketClerkLock[myIndex]);
		
		if(ticketClerkState[myIndex] == 1){
			/*STEP 2: TicketClerk-Customer, Tells Customer the total, and waits for the response (number of tickets)*/
			
			/*TODO: Check if customer can make a purchase?*/
			printf("TicketClerk %i has an order for %i and the cost is %i.\n", myIndex, ticketClerkNumToSell[myIndex],ticketClerkNumToSell[myIndex]*12);
			ticketClerkConditionVariable[myIndex]->Signal(ticketClerkLock[myIndex]);
			ticketClerkConditionVariable[myIndex]->Wait(ticketClerkLock[myIndex]);
			
			/*STEP 3: TicketClerk-Customer, Takes cash from customer, puts in register.*/
			ticketClerkRegister[myIndex] += ticketClerkNumToSell[myIndex]*12;
			
			ticketClerkNumToSell[myIndex] = 0; /*Resets to 0 inbetween transactions.*/
			
			ticketClerkConditionVariable[myIndex]->Signal(ticketClerkLock[myIndex]);
			ticketClerkConditionVariable[myIndex]->Wait(ticketClerkLock[myIndex]);
		}
		
		ticketClerkLock[myIndex]->Release();
		
		//printf("\tTC%i: i have risen\n", myIndex);
		ticketClerkBreakLock[myIndex]->Acquire();

		if(ticketClerkBreak[myIndex] == 1){ /* i should go on break */
			//printf("\tTC%i: trying to acquire the ticket clerk line lock, and i have the ticket clerk break lock\n", myIndex);
			//ticketClerkLineLock->Acquire();
			//printf("\tTC%i: ticket clerk line lock acquired\n", myIndex);
			//ticketClerkLineCount[myIndex] = 0;
			//ticketClerkLineConditionVariable[myIndex]->Broadcast(ticketClerkLineLock); /* signal to everyone in my line. need to acquire first???? MM: Yeah...I'd say acquire.*/
			//ticketClerkLineLock->Release();
			//printf("\tTC%i: ticket clerk line lock released\n", myIndex);
			printf("TicketClerk %i is going on break.\n", myIndex);
			ticketClerkBreakConditionVariable[myIndex]->Wait(ticketClerkBreakLock[myIndex]); /* wait until I am off break */
			printf("TicketClerk %i is coming off break.\n", myIndex);
		}

		ticketClerkBreakLock[myIndex]->Release();
	}
}

void concessionClerk(int myIndex){
	while(1){ /* while true */
		concessionClerkLineLock->Acquire(); /* Lock for choosing a line */
		printf("ConcessionClerk %i has a line length %i and is signaling a customer.\n", myIndex, concessionClerkLineCount[myIndex]);
		/* check if there is a customer in my line */
		if(concessionClerkLineCount[myIndex] > 0){ /* There is someone in my line */
			//printf("\t\tCC%i: Someone is in my line!\n", myIndex);
			/* Steps
			1. set my state to busy
			2. decrement line count
			3. wake up 1 customer */
			
			concessionClerkState[myIndex] = 1; /* state = BUSY */
			concessionClerkLineCount[myIndex]--; /* decrement line count */
			concessionClerkLineConditionVariable[myIndex]->Signal(concessionClerkLineLock);
		} else { /* no one is in my line */
			/* Steps
			1. set my state to not_busy */
			printf("ConcessionClerk %i has no one in line. I am available for a customer.\n", myIndex);
			
			concessionClerkState[myIndex] = 0; /* state = NOT_BUSY */
		}
		
		/* done with concession clerk's first monitor.
		   concession clerk is ready to wait
		   by acquiring the next lock before releasing the current lock,
		   we guarantee that we get the lock first */
		
		concessionClerkLock[myIndex]->Acquire();  
		concessionClerkLineLock->Release();
		
		/*STEP 1: ConcessionClerk-Customer, Waiting for the customer to come up to the counter.*/
		//printf("\t\tCC%i: Waiting for the customer to walk on up here!\n", myIndex);
		concessionClerkConditionVariable[myIndex]->Wait(concessionClerkLock[myIndex]);
		
		if(concessionClerkState[myIndex] == 1){
			/*STEP 2: ConcessionClerk-Customer, Tells customer the total*/
			
			printf("ConcessionClerk %i has an order for %i popcorn and %i soda. The cost is %i.\n", myIndex, concessionClerkPopcornToSell[myIndex], concessionClerkSodaToSell[myIndex], (concessionClerkPopcornToSell[myIndex]*5 + concessionClerkSodaToSell[myIndex]*4));

			concessionClerkConditionVariable[myIndex]->Signal(concessionClerkLock[myIndex]);
			concessionClerkConditionVariable[myIndex]->Wait(concessionClerkLock[myIndex]);
			
			/*STEP 3: ConcessionClerk-Customer, Takes cash from customer.*/
			concessionClerkRegister[myIndex] += (concessionClerkPopcornToSell[myIndex]*5 + concessionClerkSodaToSell[myIndex]*4);
			printf("ConcessionClerk %i has been paid for the order.\n", myIndex);

			
			concessionClerkPopcornToSell[myIndex] = 0;
			concessionClerkSodaToSell[myIndex] = 0;
			
			concessionClerkConditionVariable[myIndex]->Signal(concessionClerkLock[myIndex]);
			concessionClerkConditionVariable[myIndex]->Wait(concessionClerkLock[myIndex]);
		}
		
		concessionClerkLock[myIndex]->Release();
		
		concessionClerkBreakLock[myIndex]->Acquire();
		if(concessionClerkBreak[myIndex] == 1){ /* i should go on break */
			printf("ConcessionClerk %i is going on break.\n", myIndex);
			//concessionClerkLineLock->Acquire();
			//concessionClerkLineCount[myIndex] = 0;
			//concessionClerkLineConditionVariable[myIndex]->Broadcast(concessionClerkLineLock); /* signal to everyone in my line. need to acquire first???? */
			//concessionClerkLineLock->Release();
			concessionClerkBreakConditionVariable[myIndex]->Wait(concessionClerkBreakLock[myIndex]); /* wait until I am off break */
			printf("ConcessionClerk %i is coming off break.\n", myIndex);
		}

		concessionClerkBreakLock[myIndex]->Release();
	}
}

void ticketTaker(int myIndex){
	while(1){
		//printf("\t\t\tTT%i: about to acquire my ticket taker line lock\n", myIndex);
		ticketTakerLineLock->Acquire();  /* Look in line */
		printf("TicketTaker %i has a line length %i and is signaling a customer.\n", myIndex, ticketTakerLineCount[myIndex]);
		if(ticketTakerLineCount[myIndex] > 0){
			//printf("\t\t\tTT%i: Someone is in my line!\n", myIndex);
			ticketTakerState[myIndex] = 1;
			ticketTakerLineCount[myIndex]--;
			ticketTakerLineConditionVariable[myIndex]->Signal(ticketTakerLineLock);
		} else {
			printf("TicketTaker %i has no one in line. I am available for a customer.\n", myIndex);
			ticketTakerState[myIndex] = 0;
		}
		//printf("\t\t\tTT%i: trying to acquire ticket taker lock\n", myIndex);
		ticketTakerLock[myIndex]->Acquire();
		//printf("\t\t\tTT%i: acquired ticket taker lock about to release ticket taker line lock\n", myIndex);
		ticketTakerLineLock->Release();
		//printf("\t\t\tTT%i: released ticket taker line lock, about to wait on my ticket taker lock\n", myIndex);
		ticketTakerConditionVariable[myIndex]->Wait(ticketTakerLock[myIndex]);
		//printf("\t\t\tTT%i: reacquired my ticket taker lock\n", myIndex);
		
		if(ticketTakerState[myIndex] == 1){
			if(ticketTakerCounter[myIndex] <= ROW_SIZE*NUM_ROWS - numberAdmitted && movieStartTime == 0){
			//if(ticketTakerCounter[myIndex] <= 10 - numberAdmitted && movieStartTime == 0){ //testing purposes
				/* let them in */
				//printf("\t\t\tTT%i: You're good to go! Thanks brohan!\n", myIndex);
				
				printf("TicketTaker %i has received %i tickets.\n", myIndex, ticketTakerCounter[myIndex]);
				
				//printf("\t\t\tTT%i: trying to acquire movie data lock\n", myIndex);
				movieDataLock->Acquire();
				//printf("\t\t\tTT%i: acquired movie data lock\n", myIndex);
				numberAdmitted += ticketTakerCounter[myIndex];
				
				printf("TicketTaker %i is allowing the group into the theater. The number of tickets taken is %i.\n", myIndex, numberAdmitted);
				
				//printf("\t\t\tTT%i: trying to release movie data lock\n", myIndex);
				movieDataLock->Release();
				//printf("\t\t\tTT%i: released movie data lock\n", myIndex);
				
				ticketTakerCounter[myIndex] = 1;
			} else {
				/* don't let them in */
				//printf("\t\t\tTT%i: Sorry brochacho, can't let you in\n", myIndex);
				
				printf("TicketTaker %i is not allowing the group into the theater. The number of taken tickets is %i and the group size is %i.\n", myIndex, numberAdmitted, ticketTakerCounter[myIndex]);
				
				ticketTakerCounter[myIndex] = 0;
			}
		
			ticketTakerConditionVariable[myIndex]->Signal(ticketTakerLock[myIndex]);
			//printf("\t\t\tTT%i: Have a nice day!\n", myIndex);
			ticketTakerConditionVariable[myIndex]->Wait(ticketTakerLock[myIndex]);
		}
		//printf("\t\t\tTT%i: reacquired my ticket taker lock, about to release ticket taker lock\n", myIndex);
		ticketTakerLock[myIndex]->Release();
		//printf("\t\t\tTT%i: released ticket taker lock, about to check for break stuff\n", myIndex);
		
		ticketTakerBreakLock[myIndex]->Acquire();

		if(ticketTakerBreak[myIndex] == 1){ /* i should go on break */
			printf("TicketTaker %i is going on break.\n", myIndex);
			//ticketTakerLineLock->Acquire();
			//ticketTakerLineCount[myIndex] = 0;
			//ticketTakerLineConditionVariable[myIndex]->Broadcast(ticketTakerLineLock); /* signal to everyone in my line. need to acquire first???? */
			//ticketTakerLineLock->Release();
			ticketTakerBreakConditionVariable[myIndex]->Wait(ticketTakerBreakLock[myIndex]); /* wait until I am off break */
			printf("TicketTaker %i is coming off break.\n", myIndex);
		}

		ticketTakerBreakLock[myIndex]->Release();
	}
}

void technician(int myIndex){ /* doesn't really need an index but I put it because it's necessary for forking and this will make it scalable if we want more technicians */
	while(1){
		/* 
		A.	if movie conditions met, start movie
		B.	tell customers to leave room
		C.	wait for next movie data
		*/
		//printf("\t\t\t\tMT: about to acquire the movie lock\n");
		movieDataLock->Acquire();
		//printf("\t\t\t\tMT: acquired the movie lock, trying to acquire movie room lock\n");
		
		/* A. if movie conditions met, start movie
			1.	check if current time is movie start time
			2.	check if all sold tickets are accounted for
		*/
		movieRoomLock->Acquire();
		//printf("\t\t\t\tMT: acquired the movie room lock\n");
		
		//printf("\t\t\t\tMT: checking if I can play movie\n");
		if(movieStartTime == 1 && seatsFilled == numberAdmitted){ /** remove the && bit later */
			numberAdmitted = 0; 
			
			movieLength = rand() % 100 + 200;
			
			printf("The MovieTechnician has started the movie.\n");
			
		//	printf("\t\t\t\tMT: playing dat movie, I love Matt Damon. it's %i long\n", movieLength);
			for(int i = 0; i < movieLength; i++){
				currentThread->Yield(); /* used to play movie */
			}
			
			
			
			/* movie should be done at this point */
			seatsFilled = 0; 
			movieStartTime = 0;
			movieEnded = 1;
			/* B. tell customers to leave room */
			printf("The MovieTechnician has ended the movie.\n");
			
			for(int i = 0; i < NUM_ROWS; i++){
				room[i] = 0;
			}
			movieRoomConditionVariable->Broadcast(movieRoomLock);
			printf("The MovieTechnician has told all customers to leave the theater room.\n");
		}
		//printf("\t\t\t\tMT: about to release movie room lock\n");
		movieRoomLock->Release();
		/* C. wait for next movie data */
		//printf("\t\t\t\tMT: released movie room lock, waiting for my movie data\n");
		technicianDataConditionVariable->Wait(movieDataLock);
		//printf("\t\t\t\tMT: reacquired and now about to release movie data lock\n");
		movieDataLock->Release();
		//printf("\t\t\t\tMT: released movie data lock\n");
	}
}

void manager(int myIndex){
	int counter = 0;
	while(1){
		//printf("\t\t\t\t\tMANAGER\n");
		/* BEGIN: ON BREAK STUFF */
		
		/* tell the ticket clerk to go on break if need be */
		/* acquire the ticket clerk line lock to see state? */
		ticketClerkLineLock->Acquire();
		
		//printf("\t\t\t\t\tMAN: check if any TCs need a break.\n");
		for(int i = 0; i < MAX_TC; i++){
			if(ticketClerkState[i] == 1 || ticketClerkState[i] == 0){ /* if available */
				//printf("\t\t\t\t\tMAN: acquiring TC%i's break lock\n", i);
				ticketClerkBreakLock[i]->Acquire();
				
				if(ticketClerkLineCount[i] < 3){ /* if line size is < 3 */
					for(int j = 0; j < MAX_TC; j++){
						if(j != i && ticketClerkState[j] > -1 && ticketClerkBreak[j] == 0 && ticketClerkBreak[i] == 0){ /* if there is another clerk available */
							if(rand() % 100 < 20){
								printf("Manager has told TicketClerk %i to go on break.\n", i);
								//printf("\t\t\t\t\tMAN: TC%i has %i in his line, take a break!\n", i, ticketClerkLineCount[i]);
								//ticketClerkLineCount[i] = 0;
								ticketClerkLineConditionVariable[i]->Broadcast(ticketClerkLineLock);
								if(ticketClerkState[i] == 0){
									ticketClerkConditionVariable[i]->Signal(ticketClerkLock[i]);
								}
								ticketClerkState[i] = 2; /* set to "break" MM: I think you should preserve the state as not busy. */
								ticketClerkBreak[i] = 1; /* set them to on break */	
								currentThread->Yield();
								break;
							}
						}
					}
				} else if(ticketClerkLineCount[i] > 5){
					for(int j = 0; j < MAX_TC; j++){
						if(j != i && ticketClerkBreak[j] == 1 && 0){
							//printf("\t\t\t\t\tMAN: TC%i get off break, TC%i is getting slammed with %i!\n", j, i, ticketClerkLineCount[i]);
							
							ticketClerkLineConditionVariable[i]->Broadcast(ticketClerkLineLock);
							ticketClerkBreak[i] = 2; /* tell line to leave */
							//ticketClerkLineCount[i] = 0;
							ticketClerkLineCount[j] = 0;
							ticketClerkState[j] = 0; /* set to not busy */
							ticketClerkBreak[j] = 0; /* set them to off break */
							ticketClerkBreakConditionVariable[j]->Signal(ticketClerkBreakLock[j]); /** signal to come off break gets signalled even if the ticket clerk isn't waiting for on break...need to fix!*/
							currentThread->Yield();
							break;
						}
					}			
				}
				
				//printf("\t\t\t\t\tMAN: releasing TC%i's break lock\n", i);
				ticketClerkBreakLock[i]->Release();
			}
		}

		//printf("\t\t\t\t\tMAN: done checking TCs for breaks\n");
		ticketClerkLineLock->Release();
		
		/* tell the concession clerk to go on break if need be */
		/* acquire the concession clerk line lock to see state? */
		//printf("\t\t\t\t\tMAN: trying to acquire concession clerk line lock\n");
		concessionClerkLineLock->Acquire();

		//printf("\t\t\t\t\tMAN: check if any CCs need a break.\n");
		for(int i = 0; i < MAX_CC; i++){
			if(concessionClerkState[i] == 1 || concessionClerkState[i] == 0){ /* if available */
				concessionClerkBreakLock[i]->Acquire();
				
				if(concessionClerkLineCount[i] < 3){ /* if line size is < 3 */
					for(int j = 0; j < MAX_TC; j++){
						if(j != i && concessionClerkState[j] > -1 && concessionClerkBreak[j] == 0 && concessionClerkBreak[i] == 0){ /* if there is another clerk available */
							if(rand() % 100 < 20){
								//printf("\t\t\t\t\tMAN: CC%i has %i in his line, take a break!\n", i, concessionClerkLineCount[i]);
								printf("Manager has told ConcessionClerk %i to go on break.\n", i);
								//concessionClerkLineCount[i] = 0;
								concessionClerkLineConditionVariable[i]->Broadcast(concessionClerkLineLock);
								if(concessionClerkState[i] == 0){
									concessionClerkConditionVariable[i]->Signal(concessionClerkLock[i]);
								}
								concessionClerkState[i] = 2; /* set to "break" */
								concessionClerkBreak[i] = 1; /* set them to on break */
								currentThread->Yield();
								break;
							}
						}
					}
				} else if(concessionClerkLineCount[i] > 5){
					for(int j = 0; j < MAX_TC; j++){
						if(j != i && concessionClerkBreak[j] == 1 && 0){
							printf("\t\t\t\t\tMAN: CC%i get off break, CC%i is getting slammed with %i!\n", j, i, concessionClerkLineCount[i]);
							concessionClerkLineConditionVariable[i]->Broadcast(concessionClerkLineLock);
							concessionClerkBreak[i] = 2; /* tell line to leave */
							//concessionClerkLineCount[i] = 0;
							concessionClerkLineCount[j] = 0;
							concessionClerkState[j] = 0; /* set to not busy */
							concessionClerkBreak[j] = 0; /* set them to off break */
							concessionClerkBreakConditionVariable[j]->Signal(concessionClerkBreakLock[j]); /* signal to come off break */
							currentThread->Yield();
							break;
						}
					}			
				}
				
				concessionClerkBreakLock[i]->Release();
			}
		}

		//printf("\t\t\t\t\tMAN: done checking CCs for breaks\n");
		concessionClerkLineLock->Release();

		/* tell the ticket taker to go on break if need be */
		/* acquire the ticket taker line lock to see state? */
		//printf("\t\t\t\t\tMAN: trying to acquire ticket taker line lock to check for breaks\n");
		ticketTakerLineLock->Acquire();
		//printf("\t\t\t\t\tMAN: acquired ticket taker line lock to check for breaks\n");

		//printf("\t\t\t\t\tMAN: check if any TTs need a break.\n");
		for(int i = 0; i < MAX_TT; i++){
			if(ticketTakerState[i] == 1 || ticketTakerState[i] == 0){ /* if available */
				//printf("\t\t\t\t\tMAN: trying to acquire TT%i's break lock\n", i);
				ticketTakerBreakLock[i]->Acquire();
				//printf("\t\t\t\t\tMAN: acquired TT%i's break lock\n", i);
				
				if(ticketTakerLineCount[i] < 3){ /* if line size is < 3 */
					for(int j = 0; j < MAX_TT; j++){
						if(j != i && ticketTakerState[j] > -1 && ticketTakerBreak[j] == 0 && ticketTakerBreak[i] == 0){ /* if there is another taker available */
							if(rand() % 100 < 20){
								//printf("\t\t\t\t\tMAN: TT%i has %i in his line, take a break!\n", i, ticketTakerLineCount[i]);
								
								printf("Manager has told TicketTaker %i to go on break.\n",i);
								//ticketTakerLineCount[i] = 0;
								ticketTakerLineConditionVariable[i]->Broadcast(ticketTakerLineLock);
								if(ticketTakerState[i] == 0){
									ticketTakerConditionVariable[i]->Signal(ticketTakerLock[i]);
								}
								ticketTakerState[i] = 2; /* set to "break" */
								ticketTakerBreak[i] = 1; /* set them to on break */
								currentThread->Yield();
								break;
							}
						}
					}
				} else if(ticketTakerLineCount[i] > 5){
					for(int j = 0; j < MAX_TT; j++){
						if(j != i && ticketTakerBreak[j] == 1 && 0){
							//printf("\t\t\t\t\tMAN: TT%i get off break, TT%i is getting slammed with %i!\n", j, i, ticketTakerLineCount[i]);
							ticketTakerLineConditionVariable[i]->Broadcast(ticketTakerLineLock);
							ticketTakerBreak[i] = 2; /* tell line to leave */
							//ticketTakerLineCount[i] = 0;
							ticketTakerLineCount[j] = 0;
							ticketTakerState[j] = 0; /* set to not busy */
							ticketTakerBreak[j] = 0; /* set them to off break */
							ticketTakerBreakConditionVariable[j]->Signal(ticketTakerBreakLock[j]); /* signal to come off break */
							currentThread->Yield();
							break;
						}
					}			
				}
				
				ticketTakerBreakLock[i]->Release();
			}
		}

		//printf("\t\t\t\t\tMAN: about to release ticket taker line lock after checking for breaks\n");
		ticketTakerLineLock->Release();
		//printf("\t\t\t\t\tMAN: released ticket taker line lock after checking for breaks\n");
		
		/* END: ON BREAK STUFF */
	
		//printf("\t\t\t\t\tMAN: trying to acquire movie data lock\n");
		movieDataLock->Acquire();
		//printf("\t\t\t\t\tMAN: acquired movie data lock\n");
		/* lock all the ticket takers */
		//printf("\t\t\t\t\tMAN: trying to acquire ticket taker line lock to acquire ticket taker locks\n");
		ticketTakerLineLock->Acquire(); /* checking ticketTakerStates */
		//printf("\t\t\t\t\tMAN: acquired ticket taker line lock to acquire ticket taker locks\n");
		for(int i = 0; i < MAX_TT; i++){
			if(ticketTakerState[i] > -1){
				//printf("\t\t\t\t\tMAN: trying to acquire TT%i taker lock\n", i);
				ticketTakerLock[i]->Acquire();
				//printf("\t\t\t\t\tMAN: acquired TT%i taker lock\n", i);
			}
		}
		//printf("\t\t\t\t\tMAN: about to release ticket taker line lock after acquiring ticket taker locks\n");
		//ticketTakerLineLock->Release();
		//printf("\t\t\t\t\tMAN: released ticket taker line lock after acquiring ticket taker locks\n");
		
		//printf("\t\t\t\t\tMAN: can we start the movie? startNumber:%i, numberAdmitted:%i; seatsFilled:%i; movieStartTime:%i; counter:%i\n", NUM_ROWS*ROW_SIZE - 3, numberAdmitted, seatsFilled, movieStartTime, counter);
		if(numberAdmitted == seatsFilled && movieStartTime == 0 && seatsFilled != 0 && numberAdmitted > NUM_ROWS*ROW_SIZE - 3 || (counter > 100 && numberAdmitted > 0)){ //if people have been waiting in the theater for a while, start the movie
			//printf("\t\t\t\t\tMAN: yo let's get this partay started!\n");
			printf("Manager is telling the MovieTechnnician to start the movie.\n");
			technicianDataConditionVariable->Signal(movieDataLock);
			movieEnded = 0;
			movieStartTime = 1;
			
			/* check the ticket clerk registers */
			//printf("\t\t\t\t\tMAN: checking the ticket clerk registers\n");
			for(int i = 0; i < MAX_TC; i++){
				//printf("\t\t\t\t\tMAN: acquiring line lock before reading registers\n");
				ticketClerkLineLock->Acquire();
				if(ticketClerkState[i] > -1){
					ticketClerkLock[i]->Acquire();
					ticketMoney += ticketClerkRegister[i];
					printf("Manager collected %i from TicketClerk%i.\n", ticketClerkRegister[i], i);
					ticketClerkRegister[i] = 0;
					ticketClerkLock[i]->Release();
				}
				//printf("\t\t\t\t\tMAN: releasing line lock after reading registers\n");
				ticketClerkLineLock->Release();
			}
			//printf("\t\t\t\t\tMAN: we have made $%i so far from tickets\n", ticketMoney);
			
			/* check the concession clerk registers */
			//printf("\t\t\t\t\tMAN: checking the concession clerk registers\n");
			for(int i = 0; i < MAX_CC; i++){
				concessionClerkLineLock->Acquire();
				if(concessionClerkState[i] > -1){
					concessionClerkLock[i]->Acquire();
					concessionMoney += concessionClerkRegister[i];
					printf("Manager collected %i from ConcessionClerk%i.\n", concessionClerkRegister[i], i);
					concessionClerkRegister[i] = 0;
					concessionClerkLock[i]->Release();
				}
				concessionClerkLineLock->Release();
			}
			
			printf("Total money made by office = %i \n", (ticketMoney + concessionMoney));
			
			//printf("\t\t\t\t\tMAN: we have made $%i so far from concessions\n", concessionMoney);			
		}
		
		//printf("\t\t\t\t\tMAN: i forget, did a movie just finish?\n");
		if(movieEnded == 1){
		//	printf("\t\t\t\t\tMAN: movie's over! people can line up again\n");
			counter = 0;
			movieStartTime = 0;
			movieEnded = 0;
			//printf("\t\t\t\t\tMAN: about to acquire ticket taker line lock for broadcast\n");
			//ticketTakerLineLock->Acquire();
			//printf("\t\t\t\t\tMAN: acquired ticket taker line lock for broadcast\n");
			//printf("\t\t\t\t\tMAN: broadcast\n");
			lobbyConditionVariable->Broadcast(ticketTakerLineLock);
			//printf("\t\t\t\t\tMAN: about to release ticket taker line lock for broadcast\n");
			//ticketTakerLineLock->Release();
			//printf("\t\t\t\t\tMAN: released ticket taker line lock for broadcast\n");
		}
		
		/* release all the ticket clerks */
		//printf("\t\t\t\t\tMAN: trying to acquire ticket taker line lock to release ticket taker locks\n");
		//ticketTakerLineLock->Acquire(); /* checking ticketTakerStates */
		//printf("\t\t\t\t\tMAN: acquired ticket taker line lock to release ticket taker locks\n");
		for(int i = 0; i < MAX_TT; i++){
			if(ticketTakerState[i] > -1){
				//printf("\t\t\t\t\tMAN: releasing TT%i's taker lock\n", i);
				ticketTakerLock[i]->Release();
				//printf("\t\t\t\t\tMAN: released TT%i's taker lock\n", i);
			}
		}
		//printf("\t\t\t\t\tMAN: about to release ticket taker line lock to release ticket taker locks\n");
		ticketTakerLineLock->Release();
		//printf("\t\t\t\t\tMAN: released ticket taker line lock to release ticket taker locks\n");
		
		//printf("\t\t\t\t\tMAN: Waiting yo\n");
		//technicianDataConditionVariable->Wait(movieDataLock);
		//printf("\t\t\t\t\tMAN: about to release movie data lock\n");
		movieDataLock->Release();
		//printf("\t\t\t\t\tMAN: released movie data lock\n");
		
		counterLock->Acquire();
		//printf("\t\t\t\t\tMAN: custCounter = %i\n", custCounter);
		int temp = custCounter;
		counterLock->Release();
		
		if(temp == 0){
			printf("Total money made by office = %i \n", (ticketMoney + concessionMoney));
			//printf("\t\t\t\t\tMAN: closing shop, no customers left\n");
			//printf("\t\t\t\t\tMAN: we have made $%i from tickets\n", ticketMoney);
			//printf("\t\t\t\t\tMAN: we have made $%i from concessions\n", concessionMoney);	
			break;
		}
		
		counter++;
		currentThread->Yield();
	}
}

/*Initializating */
void theaterInitializations(int numTC, int numCC, int numTT, int maxCust)
{

    DEBUG('t', "Entering Movie Theater Simulation");

	printf("Movie Theater Simulation\n");
	printf("***\n");
	
	custCounter = maxCust;

	counterLock = new Lock("Counter Lock");
	
	/*BEGIN: Ticket Clerk Initialization*/
	
	ticketClerkLineLock = new Lock("TicketClerk Line Lock");
	
	for(int i = 0; i < MAX_TC; i++){
		
		if(i < numTC ){
		
			ticketClerkLineConditionVariable[i] = new Condition("TicketClerk Line CV");
			ticketClerkLineCount[i] = 0;		
			ticketClerkLock[i] = new Lock("TicketClerk Lock");
			ticketClerkConditionVariable[i] = new Condition("TicketClerk CV");
			ticketClerkRegister[i] = 0;
			ticketClerkState[i] = 0;
			
			ticketClerkBreakLock[i] = new Lock("Ticket Clerk Break Lock");
			ticketClerkBreakConditionVariable[i] = new Condition("Ticket Clerk Break Condition Variable");
			ticketClerkBreak[i] = 0;
			
			//Thread *t = new Thread("TicketClerk thread");
			//t->Fork(ticketClerk, i);
		
		}
		else{
			ticketClerkLineCount[i] = 0;	
			ticketClerkState[i] = -1;				
		}
	
	}
	
	/*END: Ticket Clerk Initialization*/
	
	/*BEGIN: Concession Clerk Initialization*/
	
	concessionClerkLineLock = new Lock("ConcessionClerk Line Lock");
	
	for(int i = 0; i < MAX_CC; i++){
		
		if(i < numCC ){
		
			concessionClerkLineConditionVariable[i] = new Condition("ConcessionClerk Line CV");
			concessionClerkLineCount[i] = 0;		
			concessionClerkLock[i] = new Lock("ConcessionClerk Lock");
			concessionClerkConditionVariable[i] = new Condition("ConcessionClerk CV");
			concessionClerkRegister[i] = 0;
			concessionClerkState[i] = 0;
			
			concessionClerkBreakLock[i] = new Lock("Concession Clerk Break Lock");
			concessionClerkBreakConditionVariable[i] = new Condition("Concession Clerk Break Condition Variable");
			concessionClerkBreak[i] = 0;
			
			//Thread *t = new Thread("ConcessionClerk thread");
			//t->Fork(concessionClerk, i);
		
		}
		else{
			concessionClerkLineCount[i] = 0;
			concessionClerkState[i] = -1;				
		}
	
	}
	
	/*END: Concession Clerk Initialization*/
	
	/*BEGIN: Ticket Taker Intializations*/
	
	ticketTakerLineLock = new Lock("Ticket Taker Line Lock");
	//numberAdmitted = 0;
	for(int i = 0; i < MAX_TT; i++){
		
		/* will now initialize for number of TixTakers */
		if(i < numTT){
			ticketTakerLineConditionVariable[i] = new Condition("Ticket Taker Line CV");
			ticketTakerConditionVariable[i] = new Condition("Ticket Taker Interaction CV");
			ticketTakerLineCount[i] = 0;
			ticketTakerCounter[i] = 0;
			ticketTakerState[i] = 0;
			ticketTakerLock[i] = new Lock("Ticket Taker Interaction Lock");
			
			ticketTakerBreakLock[i] = new Lock("Ticket Taker Break Lock");
			ticketTakerBreakConditionVariable[i] = new Condition("Ticket Taker Break Condition Variable");
			ticketTakerBreak[i] = 0;
			
			//Thread *t = new Thread("TicketTaker thread");
			//t->Fork(ticketTaker, i);
			
		} else {
			ticketTakerState[i] = -1;
			ticketTakerLineCount[i] = 0;
		}
	}
	
		/* Lobby */
	lobbyConditionVariable = new Condition("Lobby CV to get TT Line Lock");
	
	/*END: Ticket Taker Initializations*/
	
	/* BEGIN: Technician Initialization */
	
	for(int i = 0; i < NUM_ROWS; i++){
		room[i] = 0; 
	}
	
	movieRoomLock = new Lock("Movie Room Lock");
	movieRoomConditionVariable = new Condition("Movie Room Condition Variable");
	
	movieDataLock = new Lock("Movie Data Lock");
	technicianDataConditionVariable = new Condition("Technician Data Condition Variable");
	
	//Thread *tempThread = new Thread("Technician Thread");
	//tempThread->Fork(technician, 0);
	
	/* END: Technician Initialization */	
	
	/*BEGIN: Manager Initializations*/
	
	movieLength = 0;
	movieStartTime = 0;
	movieEnded = 0;
	
	//tempThread = new Thread("Manager Thread");
	//tempThread->Fork(manager, 0);
	
	/*END: Manager Initializations*/
	
	/*BEGIN: Customer Initialization*/
	
	int customersLeft = maxCust;
	
	numCustomers = 0;
	
	for ( int i=0; i < maxCust; i++ ) {
		
		/*Generate the size of the group, not counting head customer*/
		//int numFriends =  4;
		int numFriends = rand() % 5;

		if(customersLeft <= 0){
			numGroups = i-1;
			break;
		}
		
		if(customersLeft <= numFriends){
			numFriends = customersLeft - 1;
			
		}

		if(customersLeft > 0){
			/*Head Customer's Regular Customer Data (because he's a customer too)*/
			customerNumber[numCustomers] = numCustomers;
			customerGroupNumber[numCustomers] = i;
			customerWantsPopcorn[numCustomers] = -1;
			customerWantsSoda[numCustomers] = -1;
			customerNeedsBathroom[numCustomers] = -1;
			customerIsHeadCustomer[numCustomers] = 1;
			customerSeatNumber[numCustomers] = -1;
			customerHasPopcorn[numCustomers] = -1;
			customerHasSoda[numCustomers] = -1;
			
			/* Head Customer Data */		
			groupSize[i] = numFriends;
			groupPopcornSize[i] = -1;
			groupSodaSize[i] = -1;
			groupBathroomSize[i] = -1;
			groupMoney[i] = 105;
			groupTickets[i] = -1;
			headCustomerNumber[i] = i;
			customerState[i] = -1;
			customerStateLock[i] = new Lock("Customer State Lock");
			
			//Thread *t = new Thread("Head Customer");
			//t->Fork( headCustomer, i);
			
			headCustomerLock[i] = new Lock("HeadCustomer Lock");
		
			headCustomerConditionVariable[i] = new Condition("HeadCustomerCV");
			regularCustomerConditionVariable[i] = new Condition("RegularCustomerCV");
		
			numCustomers++;
			
			bathroomLock[i] = new Lock("Bathroom Lock");
				bathroomLobbyConditionVariable[i] = new Condition("Bathroom Lobby");
			
			//Now make all the regular Customers for this group
			for (int j = 0; j < numFriends; j++ ) {
				
				customerNumber[numCustomers] = numCustomers;
				customerGroupNumber[numCustomers] = i;
				customerWantsPopcorn[numCustomers] = -1;
				customerWantsSoda[numCustomers] = -1;
				customerNeedsBathroom[numCustomers] = -1;
				customerIsHeadCustomer[numCustomers] = 0;
				customerSeatNumber[numCustomers] = -1;
				customerHasPopcorn[numCustomers] = -1;
				customerHasSoda[numCustomers] = -1;
							
				//t = new Thread("Regular Customer");
				//t->Fork( regularCustomer, numCustomers );		
				
				
				
				numCustomers++;
			}
		
			customersLeft -= (numFriends + 1);		
		
		}	
	}

	/*END: Customer Initialization*/
	
	printf("Number of Customers = %i\n", maxCust);
	printf("Number of Groups = %i\n", numGroups);
	printf("Number of TicketClerks = %i\n", numTC);
	printf("Number of ConcessionClerks = %i\n", numCC);
	printf("Number of TicketTakers = %i\n", numTT);
	
	printf("***\n");
	
	/* BEGIN: Forking Threads */
	/* ticket clerk forking */
	for(int i = 0; i < MAX_TC; i++){
		if(i < numTC){
			Thread *t = new Thread("TicketClerk thread");
			t->Fork(ticketClerk, i);
		}
	}
	
	/* concession clerk forking */
	for(int i = 0; i < MAX_CC; i++){
		if(i < numCC){
			Thread *t = new Thread("ConcessionClerk thread");
			t->Fork(concessionClerk, i);
		}
	}
	
	/* ticket taker forking */
	for(int i = 0; i < MAX_TT; i++){
		if(i < numTT){
			Thread *t = new Thread("TicketTaker thread");
			t->Fork(ticketTaker, i);
		}
	}
	
	/* technician forking */
	Thread *temp = new Thread("Technician thread");
	temp->Fork(technician, 0);
	
	/* manager forking */
	temp = new Thread("Manager Thread");
	temp->Fork(manager, 0);
	
	/* customer forking */
	for(int i = 0; i < maxCust; i++){
		if(customerIsHeadCustomer[i]){
			Thread *t = new Thread("HeadCustomer thread");
			t->Fork(headCustomer, customerGroupNumber[i]);
			for(int j = 0; j < groupSize[customerGroupNumber[i]]; j++){
				t = new Thread("RegularCustomer thread");
				t->Fork(regularCustomer, i+j+1);
			}
		}
	}
	/* END: Forking Threads */
}

void runTheater(){

	/*params: TicketClerks, ConcessionClerks, TicketTaker, Customers*/
	theaterInitializations(2,2,2,60);

}


#endif
